"""安装 Template Router"""
import os
import secrets
import shutil
import sys

import fastapi
from cachetools import TTLCache
from dotenv import set_key
from fastapi import APIRouter, Depends, Form, Request
from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy import exists, insert, MetaData, select, Table
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import Session
from sse_starlette.sse import EventSourceResponse

from core.models import (
    Base, Board, Config, DB_TABLE_PREFIX, Content, FaqMaster, Group, Member,
    QaConfig
)
from core.database import DBConnect
from core.exception import AlertException
from core.formclass import InstallFrom
from core.plugin import read_plugin_state, write_plugin_state
from core.settings import ENV_PATH, settings
from install.default_values import (
    default_board_data, default_boards, default_cache_directory, default_config,
    default_contents, default_data_directory, default_faq_master, default_gr_id,
    default_group, default_member, default_qa_config, default_version
)
from lib.common import dynamic_create_write_table, read_license
from lib.dependency.dependencies import validate_install, validate_token
from lib.pbkdf2 import create_hash


INSTALL_TEMPLATES = "install/templates"

router = APIRouter(prefix="/install",
                   tags=["install"],
                   include_in_schema=False)
templates = Jinja2Templates(directory=INSTALL_TEMPLATES)
templates.env.globals["default_version"] = default_version
from cachetools import TTLCache
form_cache = TTLCache(maxsize=1, ttl=60)


@router.get("/",
            name="install_main",
            dependencies=[Depends(validate_install)]) #验证config表格必须存在
async def main(request: Request):
# “安装主页”
#python版本
    python_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
    # fastapi 版本
    fastapi_version = f"{fastapi.__version__}"
    context = {
        "request": request,
        "python_version": python_version,
        "fastapi_version": fastapi_version,
    }
    return templates.TemplateResponse("main.html", context)


@router.get("/license",
            name="install_license",
            dependencies=[Depends(validate_install)])
async def install_license(request: Request):
    """的同意页面"""
    context = {
        "request": request,
        "license": read_license(),
    }
    return templates.TemplateResponse("license.html", context)


@router.get("/form",
            dependencies=[Depends(validate_install)])
async def redirect_licence(request: Request):
    """到同意书的页面 Redirect"""
    return RedirectResponse(url=request.url_for("install_license"))


@router.post("/form",
             name="install_form",
             dependencies=[Depends(validate_install)])
async def install_form(request: Request, agree: str = Form(None)):
    """安装表单页面"""
    if agree != "同意":
        raise AlertException("你必须同意莱斯。.", 400)
    context = {
        "request": request,
    }
    return templates.TemplateResponse("form.html", context)


@router.post("/",
             name="install",
             dependencies=[Depends(validate_token),
                           Depends(validate_install)])
async def install(
    request: Request,
    form_data: InstallFrom = Depends(),
):
    # “在安装开始前连接和初始化数据库”
    try:
      
        if os.path.exists("example.env"):
            shutil.copyfile("example.env", ENV_PATH)  #如果存在example.env文件，请将其复制到.env文件

        # .env 将数据库信息添加到文件   将数据库信息添加到.env文件
        set_key(ENV_PATH, "DB_ENGINE", form_data.db_engine)
        set_key(ENV_PATH, "DB_HOST", form_data.db_host)
        set_key(ENV_PATH, "DB_PORT", form_data.db_port, quote_mode="never")
        set_key(ENV_PATH, "DB_USER", form_data.db_user)
        set_key(ENV_PATH, "DB_PASSWORD", form_data.db_password)
        set_key(ENV_PATH, "DB_NAME", form_data.db_name)
        set_key(ENV_PATH, "DB_TABLE_PREFIX", form_data.db_table_prefix)
        # .env 会话密钥设置  设置.env会话密钥
        session_secret_key = secrets.token_urlsafe(50)
        set_key(ENV_PATH, "SESSION_SECRET_KEY", session_secret_key)

        # Settings 到类 .env 应用文件设置   将.env文件设置应用于Settings类
        settings.DB_ENGINE = form_data.db_engine
        settings.DB_HOST = form_data.db_host
        settings.DB_PORT = form_data.db_port
        settings.DB_USER = form_data.db_user
        settings.DB_PASSWORD = form_data.db_password
        settings.DB_NAME = form_data.db_name
        settings.DB_TABLE_PREFIX = form_data.db_table_prefix
        settings.SESSION_SECRET_KEY = session_secret_key

        # 数据库连接设置
        db = DBConnect()
        db.set_connect_infomation()
        db.create_url()
        if not db.supported_engines.get(form_data.db_engine.lower()):
            raise Exception("选择支持的数据库引擎.")  #请选择支持的数据库引擎

        # 创建和测试新的数据库连接  创建和测试新的数据库连接
        db.create_engine()
        connect = db.engine.connect()
        connect.close()

        # 激活插件  初始化插件激活
        plugin_list = read_plugin_state()
        for plugin in plugin_list:
            plugin.is_enable = False
        write_plugin_state(plugin_list)

        form_cache.update({"form": form_data})

        # 会话初始化  初始化会话
        request.session.clear()

        return templates.TemplateResponse("result.html", {"request": request})

    except OperationalError as e:
        os.remove(ENV_PATH)
        message = e._message().replace('"', r'\"').strip()
        raise AlertException(f"安装失败. 数据库连接失败.\\n{message}") from e

    except Exception as e:
        os.remove(ENV_PATH)
        raise AlertException(f"安装失败.\\n{e}") from e


@router.get("/process",
            dependencies=[Depends(validate_token)])
async def install_process(): #针对这里的困惑是这样的，这个返回的函数是个事件处理器，他会进入一个循环返回所有的yield；
    """
    安装进度事件流
    """
    async def install_event():
        db_connect = DBConnect()
        engine = db_connect.engine
        yield "完成数据库连接"  “数据库连接完成”

        try:
            form_data: InstallFrom = form_cache.get("form")

            # 更改表名称&更新元数据
            tables = Base.metadata.tables.values()
            for table in tables:
                new_table_name = table.name.replace("g6_", form_data.db_table_prefix)
                table.name = new_table_name

            if form_data.reinstall:
                Base.metadata.drop_all(bind=engine)
                # 前缀 + 'write_' 删除所有公告板表  删除所有前缀+“write_”公告栏表格
                metadata = MetaData()
                metadata.reflect(bind=engine)
                table_names = metadata.tables.keys()
                for name in table_names:
                    if name.startswith(f"{DB_TABLE_PREFIX}write_"):
                        Table(name, metadata, autoload=True).drop(bind=engine)

                yield "完全删除现有数据库表"   #“已完成删除现有数据库表”

            Base.metadata.create_all(bind=engine)
            yield "完成数据库表创建" #“数据库表创建完成”

            with db_connect.sessionLocal() as db:
                config_setup(db, form_data.admin_id, form_data.admin_email)
                if not form_data.is_skip_admin:
                    admin_member_setup(db, form_data.admin_id, form_data.admin_name,
                                    form_data.admin_password, form_data.admin_email)
                content_setup(db)
                qa_setup(db)
                faq_master_setup(db)
                board_group_setup(db)
                board_setup(db)
                db.commit()
                yield "完成基本设置信息"   #“完成首选项信息输入”

            for board in default_boards:
                dynamic_create_write_table(board['bo_table'], create_table=True)
            yield "完成公告板表的创建"  #“公告栏表格创建完成”

            setup_data_directory()
            yield "完成数据路径创建"

            yield f"[success] 我祝贺你，. {default_version} 安装完成."

        except Exception as e:
            os.remove(ENV_PATH)
            yield f"[error] 安装失败. {e}"
            raise

    # 运行事件流的安装进度  运行安装进度事件流
    return EventSourceResponse(install_event())  


def config_setup(db: Session, admin_id, admin_email):
    # """注册环境设置默认值"""  “注册首选项默认值”
    exists_config = db.scalar(
        exists(Config)
        .where(Config.cf_id == 1).select()
    )
    if not exists_config:
        db.execute(
            insert(Config).values(
                cf_admin=admin_id,
                cf_admin_email=admin_email,
                **default_config
            )
        )


def admin_member_setup(db: Session, admin_id: str, admin_name : str,
                       admin_password: str, admin_email: str):
    """顶级经理注册"""
    admin_member = db.scalar(
        select(Member).where(Member.mb_id == admin_id)
    )
    if admin_member:
        admin_member.mb_password = create_hash(admin_password)
        admin_member.mb_name = admin_name
        admin_member.mb_email = admin_email
    else:
        db.execute(
            insert(Member).values(
                mb_id=admin_id,
                mb_password=create_hash(admin_password),
                mb_name=admin_name,
                mb_nick=admin_name,
                mb_email=admin_email,
                **default_member
            )
        )


def content_setup(db: Session):
    """内容默认注册"""
    for content in default_contents:
        exists_content = db.scalar(
            exists(Content)
            .where(Content.co_id == content['co_id']).select()
        )
        if not exists_content:
            db.execute(insert(Content).values(**content))


def qa_setup(db: Session):
    """Q&A 注册默认值"""
# “注册Q&A默认值”

    exists_qa = db.scalar(
        exists(QaConfig).select()
    )
    if not exists_qa:
        db.execute(insert(QaConfig).values(**default_qa_config))


def faq_master_setup(db: Session):
    # “FAQ Master默认注册”
    """FAQ Master 注册默认值"""
    exists_faq_master = db.scalar(
        exists(FaqMaster)
        .where(FaqMaster.fm_id == 1).select()
    )
    if not exists_faq_master:
        db.execute(insert(FaqMaster).values(**default_faq_master))


def board_group_setup(db: Session):
    """创建公告板组默认"""
    # “创建公告栏组默认值”

    exists_board_group = db.scalar(
        exists(Group)
        .where(Group.gr_id == default_gr_id).select()
    )
    if not exists_board_group:
        db.execute(insert(Group).values(**default_group))


def board_setup(db: Session):
    # “创建公告栏默认值和表格”
    for board in default_boards:
        exists_board = db.scalar(
            exists(Board)
            .where(Board.bo_table == board['bo_table']).select()
        )
        if not exists_board:
            query = insert(Board).values(**board, **default_board_data)
            db.execute(query)

import shutil
def setup_data_directory():
    # “初始化数据路径”
    # 创建数据路径                          
    os.makedirs(default_data_directory, exist_ok=True)
    # 空缓存目录 #清除缓存目录
    if os.path.exists(default_cache_directory):
        shutil.rmtree(default_cache_directory)
    # 缓存目录创建  #创建缓存目录
    os.makedirs(default_cache_directory)
